/**
 * 框架国际化默认地址
 * @type {{dataTables: string}}
 */
var GlobalLang = {
    dataTables : ctx+'/resources/lib/datatables/i18n/Chinese.json'
};
var DataTables = {
    /**显示附加信息到表格底部*/
    bottomDom:"<'row'<'col-sm-12'tr>>" +
    "<'row'<'col-sm-5'li><'col-sm-7'p>>"
};
$.fn.datepicker.defaults.format = 'yyyy-mm-dd';
$.fn.datepicker.defaults.language = 'zh-CN';

_DEBUG = true; // 日志开关
function log(msg) {
    if (!console.log) {
        return;
    }
    try {
        if (_DEBUG == true) {
            var mm = (typeof msg == "object" ? objToString(msg, ",") : msg);
            var name = log.caller.name;
            if (null != name && name != '') {
                console.log((new Date().toLocaleString()) + ' ' + name
                    + '()==>' + mm);
            } else {
                console.log((new Date().toLocaleString()) + '==>' + mm);
            }
        }
    } catch (e) {
    }
}

String.prototype.trim = function () {
    return this.replace(/(^\s*)|(\s*$)/g, "");
};
/**
 * 是否以指定的字符串结尾
 *
 * @param {}
 *            substring
 * @return {}
 */
String.prototype.startsWith = function (substring) {
    var reg = new RegExp("^" + substring);
    return reg.test(this);
};

/**
 * 是否以指定的字符串结束
 *
 * @param {}
 *            substring
 * @return {}
 */
String.prototype.endsWith = function (substring) {
    var reg = new RegExp(substring + "$");
    return reg.test(this);
};
/**
 * 日期格式化方法
 * // 对Date的扩展，将 Date 转化为指定格式的String
 // 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符，
 // 年(y)可以用 1-4 个占位符，毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
 // 例子：
 // (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
 // (new Date()).Format("yyyy-M-d h:m:s.S")      ==> 2006-7-2 8:9:4.18
 */
Date.prototype.format = function (fmt) {
    // author: meizz
    var o = {
        "M+": this.getMonth() + 1, // 月份
        "d+": this.getDate(), // 日
        "h+": this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, //小时
        "H+": this.getHours(), //小时
        "m+": this.getMinutes(), // 分
        "s+": this.getSeconds(), // 秒
        "q+": Math.floor((this.getMonth() + 3) / 3), // 季度
        "S": this.getMilliseconds()//毫秒
        // 毫秒
    };
    if (/(y+)/.test(fmt))
        fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        }
    return fmt;
};
var utils = {
    /**
     * 获取boolean值
     * @param val
     * @param trueVal for none true value
     */
    getBoolean: function (val, trueVal, falseVal) {
        trueVal = null == trueVal ? true : trueVal;
        falseVal = null == falseVal ? false : falseVal;

        if (utils.isNull(val) || typeof val == 'undefined') {
            return falseVal;
        }
        val = val.toLowerCase();
        if (typeof val == 'boolean') {
            return val;
        } else if (typeof val == 'string') {
            if (isNaN(parseFloat(val))) {
                if (val == 'true' || val == 'on' || val == 'yes' || val == 'y') {
                    return trueVal;
                } else {
                    return falseVal;
                }
            } else {
                if (parseFloat(val) > 0) {
                    return trueVal;
                } else {
                    return falseVal;
                }
            }
        } else if (typeof val == 'number') {
            if (val > 0) {
                return trueVal;
            } else {
                return falseVal;
            }
        } else {
            return falseVal;
        }
    },

    /**
     * 判断指定的字符串是否为null
     *
     * @param {}
     *            str
     * @return {Boolean}
     */
    isNull: function (obj) {
        if (null == obj || undefined == obj) {
            return true;
        }
        return false;
    },
    /**
     * 判断给定的字符是否是空串或者null
     *
     * @param {String}
     *            str
     * @return {Boolean} TRUE：包含非空字符
     */
    isBlank: function (str) {
        if (utils.isNull(str)) {
            return true;
        }
        if (str.trim() == '') {
            return true;
        }
        return false;
    },
    /**
     * 处理空字符串
     *
     * @param {}
     *            str
     * @return {String}
     */
    trimNull: function (str) {
        if (utils.isNull(str)) {
            return "";
        }
        return str;
    },
    uid: 0,
    /**
     * 获取一个id
     *
     * @return {}
     */
    genUid: function () {
        return 'uid-' + (++utils.uid);
    },
    /**
     * 调整url链接地址,如果不是以/开头的链接加上ctx
     *
     * @param {String}
     *            url
     */
    adjustUrl: function (url) {
        //绝对地址，直接返回
        if (url.startsWith('http')) {
            return url;
        }
        //相对地址，处理
        if (document.ctx == '/') {
            if (url.startsWith("/")) {
                return url;
            } else {
                return '/' + url;
            }
        } else {
            if (url.startsWith(document.ctx)) {
                return url;
            } else if (url.startsWith("/")) {
                return document.ctx + url;
            } else {
                return document.ctx + '/' + url;
            }
        }
    },
    /**
     * 刷新当前页面
     */
    refreshPage: function () {
        window.location.reload(true);
    },
    /**
     * 刷新指定id的iframe
     *
     * @param {}
     *            fid
     */
    refreshIFrame: function (fid) {
        log('刷新iframe预览页面 ' + fid);
        var frame = $('#' + fid);
        var src = frame.attr('src');
        frame.attr('src', '');
        frame.attr('src', src);
    },
    /**
     * 获取当前窗口的domain
     * <p>
     * http://www.jrcb.com http://232.234.3.4:8080
     *
     * @returns {String}
     */
    getWindowDomain: function () {
        var lc = window.location;
        var dm = lc.protocol + '//' + lc.host;
        return dm;
    },
    /**
     * 显示一个提示窗口
     *
     * @param {String}
     *            msg
     */
    alert: function (msg) {
        var dfd = $.Deferred();
        setTimeout(function () {
            alert(msg);
            dfd.resolve();// 可传递多个成功返回参数，
        }, 0);
        return dfd.promise();
    },
    /**
     * 显示一个确认提示框
     */
    confirm: function (msg, title) {
        title = title||'确认操作吗？';
        var dfd = $.Deferred();
        setTimeout(function () {
            if (confirm(msg)) {
                dfd.resolve(true);
            } else {
                dfd.reject(false);
            }
        }, 0);
        return dfd.promise();
    },
    /**
     * 将一个对象输出为一个字符串
     *
     * @param {}
     *            obj 要转换为字符串的对象
     * @param {}
     *            spliter 各个属性间的分隔符,默认分隔符为逗号（,）
     * @return {} 一个字符串
     */
    objToString: function (obj, spliter) {
        var spr = spliter || ',';
        var arr = [];
        for (var p in obj) {
            if (obj.hasOwnProperty(p)) {
                arr.push(p + ':' + obj[p]);
            }
        }
        return arr.join(spr);
    },
    /**
     * convert long data value to date string
     */
    long2Date: function (data) {
        var dval = new Number(data);
        var date = new Date();
        date.setTime(dval);
        return date.format('yyyy-MM-dd');
    },
    /**
     * convert long data value to time string
     */
    long2Time: function (data) {
        var dval = new Number(data);
        var date = new Date();
        date.setTime(dval);
        return date.format('HH:mm:ss');
    },
    /**
     * convert long data value to date-time string
     */
    long2DateTime: function (data) {
        var dval = new Number(data);
        var date = new Date();
        date.setTime(dval);
        return date.format('yyyy-MM-dd HH:mm:ss');
    },
    /**
     * 将数组转换为字符串，用“，”隔开
     *
     * @param values
     * @returns {String}
     */
    array2Str: function (values) {
        if (values == null) {
            return "";
        }

        var ids = "";
        if (values instanceof Array) {
            ids = values.join();
        } else if (typeof values == 'string') {
            ids = values;
        }
        return ids;
    },
    /**
     * 获取页面滚动条上部的偏移量
     *
     * @return {}
     */
    getScrollTop: function () {
        return $(document).scrollTop()
    },
    /**
     * 插入移动节点
     * @param nodes 要移动对象所在数组
     * @param fromPos 移动对象位置
     * @param toPos 要插入移动的位置
     */
    insertMoveItem : function(nodes, fromPos, toPos) {
        if(fromPos == toPos) {
            return;
        }
        var moveNode = nodes[fromPos];
        if(fromPos > toPos) {
            // 从后移动插入到前
            for (var i = fromPos; i > toPos; i--) {
                nodes[i] = nodes[i-1];
            }
        } else {
            // 从前移动插入到后面
            for (var i = fromPos; i < toPos - 1; i++) {
                nodes[i] = nodes[i+1];
            }
        }
        nodes[toPos] = moveNode;
    },
    /**
     * 判断给定的字符串是否是身份证号
     * @param str
     * @returns {boolean}
     */
    isIdNo: function (str) {
        if(utils.isBlank(str)) {
            return false;
        }
        return /^(\d{18}|\d{15}|\d{17}x)$/.test( str );
    }
};


var events = {
    /**
     * 获取方法 的事件对象
     *
     * @return {event}
     */
    getEvent: function () {
        if (document.all) {// IE
            return window.event;
        }
        var func = utils.getEvent.caller; // 返回调用本函数的函数
        while (func != null) {
            // Firefox 中一个隐含的对象 arguments，第一个参数为 event 对象
            var arg0 = func.arguments[0];
            // alert('参数长度：' + func.arguments.length);
            if (arg0) {
                if ((arg0.constructor == Event || arg0.constructor == MouseEvent)
                    || (typeof (arg0) == "object" && arg0.preventDefault && arg0.stopPropagation)) {
                    return arg0;
                }
            }
            func = func.caller;
        }
        return null;
    },

    /**
     * 清除事件冒泡
     *
     * @param {}
     *            ev 要清除的事件，如果没有指定，将清除默认的事件
     */
    clearEvent: function (ev) {
        if (null == ev) {
            ev = getEvent();
        }
        if (null == ev)
            return;
        try {
            if (window.event) {// IE
                ev.cancelBubble = true;// 停止冒泡
                ev.returnValue = false;// 阻止事件的默认行为
            } else {// 非IE
                ev.preventDefault();// 取消事件的默认行为
                ev.stopPropagation();// 阻止事件传播
            }
        } catch (e) {
        }
    },
    /**
     * 根据事件获取事件鼠标位置
     *
     * @param {}
     *            event 鼠标事件
     */
    getMousePos: function (event) {
        var xPos, yPos;
        var evt = event || window.event;
        if (evt.pageX) {
            xPos = evt.pageX;
            yPos = evt.pageY;
        } else {
            xPos = evt.clientX + document.body.scrollLeft
                - document.body.clientLeft;
            yPos = evt.clientY + document.body.scrollTop - document.body.clientTop;
        }
        return {
            'x': xPos,
            'y': yPos
        };
    }
};
/**
 * html form or input elements related common functions
 * @type {{getFormValue: Function, setFormValue: Function}}
 */
var forms = {
    /**
     * 获取所有Input元素值值
     * 默认不取带有ignore class的对象
     * 默认不取disabled的对象
     *
     * @param {String}
     *            cntId 表单或者窗口id
     * @param {Boolean} encodeString 是否表单中的字符串值进行URL ENCODING
     * @returns {Object} 所有Input元素的值
     */
    getFormValue: function (cntId, encodeString) {
        var datas = {};
        encodeString = null == encodeString ? false : !!encodeString;
        var target = _getTarget(cntId);
        if (utils.isNull(target)) {
            log('未定位到容器：' + cntId);
            return null;
        }
        target.find(':input').not('.ignore').each(function () {
            var $ele = $(this);
            // 过滤disabled对象
            if ($ele.attr('disabled')) {
                return;
            }

            var name = $ele.attr('name'), value = null;
            if(utils.isNull(name)) {
                return;
            }
            if ($ele.is(':radio') || $ele.is(':checkbox')) {
                if ($ele.is(':checked')) {
                    if ('' != $ele.val()) {
                        value = $ele.val();
                    } else {
                        value = 1;
                    }
                } else {
                    value = 0;
                }
            } else {
                value = $ele.val();
            }
            if (typeof value == 'string' && encodeString) {
                value = encodeURIComponent(value);
            }
            if (null != value) {
                datas[name] = value;
            }
        });

        return datas;
    },

    /**
     * 设置目标对象内所有Input元素的值
     *
     * @param {String}
     *            targetObj
     * @param {Object}
     *            datas 原数据组对象（object或者JSON对象）
     * @param {Object} params 设置值参数
     *  <p>propKey:设置值时使用元素的哪个属性名称
     *  <p>filter 从targetObj中如何过滤元素，可以参考JQuery的“选择器”节点，参数jQuery.find()方法
     */
    setFormValue: function (targetObj, datas, params) {
        if (utils.isNull(datas) || utils.isNull(targetObj)) {
            return;
        }
        var opts = $.extend({}, {
            "propKey": 'name',
            'filter': ':input'
        }, params || {});

        var target = _getTarget(targetObj);
        if (utils.isNull(target)) {
            log('未定位到容器：' + targetObj);
            return;
        }

        target.find(opts.filter).each(function () {
            var $ele = $(this);
            if ($ele.is(':button')) {
                return;
            }
            var name = $ele.attr(opts.propKey);
            if (null == datas[name]) {
                return;
            }
            if ($ele.is(':input')) {
                if ($ele.is(':radio') || $ele.is(':checkbox')) {
                    var value = $ele.val();
                    var flag = false;
                    if (value != '') {
                        flag = value == datas[name];
                    } else {
                        flag = !!datas[name];
                    }
                    $ele.prop('checked', flag);
                } else {
                    $ele.val(datas[name]);
                }
            } else {
                $ele.text(datas[name]);
            }
        });
    },
    /**
     * 设置select对象选项列表
     * @param targetObj 目标选择对象
     * @param optionsData 新的选项数据
     * @param keepEmpty 是否保持空选项
     * @param appendFlag 追加模式标志 默认为清空原有选项
     */
    setSelectOptions: function(targetObj, optionsData, keepEmpty, appendFlag) {
        targetObj = _getTarget(targetObj);
        if (null == targetObj || null == optionsData) {
            log('选择框或者选项数据数组为空！');
            return;
        }
        var oldVal = targetObj.val() || targetObj.data('value');
        appendFlag = (null == appendFlag ? false : appendFlag);
        if (!appendFlag) {
            targetObj.empty();
        }
        //处理空选项(保留空选项模式)
        if (null != keepEmpty && keepEmpty) {
            if (appendFlag) {
                //原有选项中是否包含空选项标志
                var hasEmptyOptionFlag = false;
                targetObj.each(function () {
                    if ($(this).val() == '') {
                        hasEmptyOptionFlag = true;
                        return false;
                    }
                });
                if (!hasEmptyOptionFlag) {
                    targetObj.prepend($('<option value="">--请选择--</option>'));
                }
            } else {
                targetObj.prepend($('<option value="">--请选择--</option>'));
            }
        }
        for (var k in optionsData) {
            if (k == '') {
                continue;
            }
            var option = $("<option></option>").val(k).text('[' + k + ']' + optionsData[k]);
            if(k == oldVal) {
                option.prop('selected', true);
            }
            targetObj.append(option);
        }
        targetObj.trigger('change');
    }
}

var dicts = {
    _CACHE: {},
    /**
     * 加载字典并缓存起来
     *
     * @param dictIds {Array}
     *            字典查询
     * @param queryIds {Array}
     *            用户自定义查询字典
     */
    loadDicts: function (dictIds, queryIds) {
        var url = ctx + '/common/dict/loadDicts.do';
        var pms = {
            'dicts': utils.array2Str(dictIds),
            'querys': utils.array2Str(queryIds)
        };
        var dfd = $.Deferred();
        jQuery.ajax({
            url: url,
            type: 'GET',
            async: false,
            dataType: 'json',
            data: pms,
            success: function (resp) {
                if (resp && resp.status) {
                    var datas = resp.data;
                    for (var k in resp.data) {
                        dicts._CACHE[k] = resp.data[k];
                    }
                    dfd.resolve('success');
                } else {
                    log('后台异常：' + resp.data);
                    dfd.reject('fail');
                }
            },
            error: function (xhr, e1, e2) {
                alert("加载字典数据异常！");
                dfd.reject('fail');
            }
        });
        return dfd.promise();
    },
    /**
     * 获取字典数据
     *
     * @param dictId 字典编号
     * <p>附加参数
     * <p>{Object} pms {}查询参数
     * <p>{boolean} useCache(true)
     * getDict(dictId,{},true);
     * @return {Object} 字典数据或者null
     */
    getDict: function (dictId) {
        var useCache = true;
        var pms = {};
        if (arguments.length == 2) {
            if (typeof arguments[1] == 'boolean') {
                useCache = !!arguments[1];
            } else if (typeof arguments[1] == 'object') {
                pms = $.extend({}, arguments[1]);
            }
        } else if (arguments.length > 2) {
            pms = $.extend({}, arguments[1]);
            useCache = !!arguments[2];
        }
        var dcdata = dicts._CACHE[dictId];
        if (useCache && null != dcdata) {
            return dcdata;
        }
        var url = ctx + '/common/dict/getDict.do';
        if (null == dcdata || useCache == false) {
            jQuery.ajax({
                url: url,
                type: 'GET',
                async: false,
                dataType: 'json',
                data: pms,
                success: function (resp) {
                    if (resp && resp.status) {
                        dcdata = dicts._CACHE[dictId] = resp.data;
                    }
                },
                error: function (xhr, e1, e2) {
                    alert("加载字典数据异常！");
                }
            });
        }
        return dcdata;
    },
    /**
     * 获取查询字典数据
     *
     * @param queryId 字典编号
     * <p>附加参数
     * <p>{Object} pms {}查询参数
     * <p>{boolean} useCache(true)
     * getQueryDict(queryId,{},true);
     * @return {Object} 字典数据或者null
     */
    getQueryDict: function (queryId) {
        var useCache = true;
        var pms = {};
        if (arguments.length == 2) {
            if (typeof arguments[1] == 'boolean') {
                useCache = !!arguments[1];
            } else if (typeof arguments[1] == 'object') {
                pms = $.extend({}, arguments[1]);
            }
        } else if (arguments.length > 2) {
            pms = $.extend({}, arguments[1]);
            useCache = !!arguments[2];
        }
        var dcdata = dicts._CACHE[queryId];
        if (useCache && null != dcdata) {
            return dcdata;
        }
        var url = ctx + '/common/dict/getQueryDict.do';
        jQuery.ajax({
            url: url,
            type: 'GET',
            async: false,
            dataType: 'json',
            data: pms,
            success: function (resp) {
                if (resp && resp.status) {
                    dcdata = dicts._CACHE[queryId] = resp.data;
                }
            },
            error: function (xhr, e1, e2) {
                alert("加载字典数据异常！");
            }
        });
        return dcdata;
    },
    /**
     * 查询字典或者查询id及相应的值，获取对应的字符串值
     * @param key
     * @param value
     * @return {String}
     */
    getDictItemValue: function (key, value) {
        var dict = dicts._CACHE[key];
        if (null != dict) {
            return dict[value];
        } else {
            return key;
        }
    },
    /**
     * set dict values to a select object
     * @param selObj select对象标识
     * @param dict 字典名称
     * @param keepEmpty
     * @param appendFlag
     */
    dictToSelect: function (selObj, dict, keepEmpty, appendFlag) {
        var datas = dicts._CACHE[dict];
        forms.setSelectOptions(selObj, datas, keepEmpty, appendFlag);
    }
}
/**
 * ztree 相关辅助方法
 * @type {{getTreeNodeFullPath: Function, sortTreeNode: Function}}
 */
var ztree = {
    /**
     * 获取Ztree节点全路径名
     * @param node ZTree节点
     * @param labelName 准备获取显示的参数名称
     * @returns {string}全路径
     */
    getTreeNodeFullPath: function (node, labelName) {
        labelName = labelName || 'name';
        var arr = [];
        if (null != node) {
            var tempNode = node;
            while (null != tempNode.getParentNode()) {
                arr.push(tempNode[labelName]);
                tempNode = tempNode.getParentNode();
            }
            arr.push(tempNode[labelName]);
        }
        if (arr.length > 0) {
            arr.reverse();
        }
        return arr.join('>>');
    },
    /**
     * 对Ztree树节点进行排序
     * @param treeObj zTree对象
     * @param node 排序开始节点
     * @param compareName 排序比较属性
     */
    sortTreeNode : function (treeObj, node, compareName) {
        if (utils.isNull(node)) {
            return;
        }
        var nodes = node.children;
        if (utils.isNull(nodes) || nodes.length < 2) {
            //少于2个节点的不用排序
            return;
        }
        //选出最小的在前面
        for (var i = 0; i < nodes.length-1; i++) {
            var j = i+1,
                curNode = nodes[i],
                moveNode = null,
                movePos = j;
            var minVal = curNode[compareName];
            for (; j < nodes.length; j++) {
                if (minVal > nodes[j][compareName]) {
                    minVal = nodes[j][compareName];
                    moveNode = nodes[j];
                    movePos = j;
                }
            }
            if(null != moveNode) {
                log('move node:'+moveNode.name+'_'+moveNode.viewIndex+' before node:'+nodes[i].name+'_'+moveNode.viewIndex);
                treeObj.moveNode(curNode, moveNode, "prev");//会改变节点的数组顺序
            }
        }
        //选出最小的在前面
        for (var i = 0; i < nodes.length; i++) {
            ztree.sortTreeNode(treeObj, nodes[i], compareName);
        }
    }
};
/**
 * dataTables相关辅助方法
 * @type {{setTrId: Function}}
 */
var dataTables = {
    /**
     * 默认的 createdRow 回调函数，此函数用于设置TR对象的data-id属性，
     * 引用此方法需要确保数据对象有ID属性
     * @param tr
     * @param data
     * @param dataIndex
     */
    setRowId: function (tr, data, dataIndex) {
        $(tr).attr('data-id', data.id);
    }
};
/**
 * 根据鼠标事件获取弹出菜单对象位置
 * @param e
 * @param menuDiv
 * @return {"position":"absolute","z-index":9999,"top":100,"left":150}
 */
function getMenuPosition(e, menuDiv) {
    var mouseX       = e.clientX
        , mouseY     = e.clientY
        , boundsX    = $(window).width()
        , boundsY    = $(window).height()
        , menuWidth  = menuDiv.find('.dropdown-menu').outerWidth()
        , menuHeight = menuDiv.find('.dropdown-menu').outerHeight()
        , tp         = {"position": "absolute", "z-index": 9999}
        , Y, X, parentOffset;

    if (mouseY + menuHeight > boundsY) {
        Y = {"top": mouseY - menuHeight + $(window).scrollTop()};
    } else {
        Y = {"top": mouseY + $(window).scrollTop()};
    }

    if ((mouseX + menuWidth > boundsX) && ((mouseX - menuWidth) > 0)) {
        X = {"left": mouseX - menuWidth + $(window).scrollLeft()};
    } else {
        X = {"left": mouseX + $(window).scrollLeft()};
    }

    // If context-menu's parent is positioned using absolute or relative positioning,
    // the calculated mouse position will be incorrect.
    // Adjust the position of the menu by its offset parent position.
    parentOffset = menuDiv.offsetParent().offset();
    X.left = X.left - parentOffset.left;
    Y.top = Y.top - parentOffset.top;

    return $.extend(tp, Y, X);
}

/** **********改写通用的提示信息、窗口*********************************** */
/**
 * 根据标识获取对象
 * @param obj 对象标识，id，class，或者jquery对象
 * @returns {jQuery Object}
 * @private
 */
function _getTarget(obj) {
    var target;
    var datas = {};
    if (typeof obj == 'string') {
        if (obj.startsWith('#') || obj.startsWith('.')) {
            target = $(obj);
        } else {
            target = $('#' + obj);
        }
    } else if(obj instanceof jQuery) {
        target = obj;
    } else {
        target = $(obj);
    }
    if (target.length == 0) {
        return null;
    }
    return target;
}

/**
 * 从HTML模板文件获取、生成Bootstrap Dialog 内容
 * @param {jQuery Object}fromTpl
 * @param {} datas
 * @returns {*|jQuery|HTMLElement}
 */
function getBSDialogContent(fromTpl, datas) {
    var node = $('<div></div>');
    node.append(fromTpl.html());
    forms.setFormValue(node, datas);
    return node;
}


/*
验证规则
 */
$(function () {
    if($.validator && $.validator.methods) {
        //
        $.validator.addMethod( "idno", function( value, element ) {
            return this.optional( element ) || /^(\d{18}|\d{15}|\d{17}x)$/.test( value );
        }, "请输入正确的身份证号" );
    }


});